/*Copyright (C) 2009 - 2011 MASSART GAUTHIER

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "../headers.h"

void cas_main(void) {
	int matrice[CAS_DEBUT_MAT_X][CAS_DEBUT_MAT_Y] = {{0}};
	int xAct = 0, yAct = 0;
	int sensAct = 0, nbAct = 0;
	int action = ERR;
	int niveau = 0, level = 0;
	float delai[16] = {400, 300, 250, 215, 175, 150, 130, 115, 100, 90, 75, 70, 65, 60, 55, 50};
	float vitesse = 1;
	CSLP_CLOCK clockT;
	double dernierT = 0;

	cas_init();
	nbAct = CAS_NB_BLOCK_DEBUT;
	yAct = CAS_HAUTEUR_MAT - 1;
	CSLP_ResetClock(&clockT);

	cas_new_line(&xAct, &yAct, matrice, &sensAct, nbAct);
	cas_afficher(matrice, nbAct, level, niveau);
	dernierT = CSLP_GetElapsedTime(clockT);

	while(1) {
		action = cas_recupEvent();

		if(nbAct == 0) {
			jouer_son(PERDU);
			CSLP_Color(COLOR_RED, COLOR_RED);
			cas_perdu_anim(matrice);
			cas_couleur_level(0, 0);
			cas_resize_cadre_anim(CAS_POS_MAT_X - 2,
			CAS_POS_MAT_Y - 1,
			(CAS_LARGEUR_BLOCK + 2) * (CAS_LARGEUR_MAT) + 1,
			(CAS_HAUTEUR_BLOCK + 2) * (CAS_HAUTEUR_MAT),
			CAS_PLEIN, (level % 5) * (CAS_LARGEUR_BLOCK + 2));
			CAS_LARGEUR_MAT = CAS_DEBUT_MAT_X;
			CAS_POS_MAT_X = CAS_DEBUT_POS_X;
			nbAct = CAS_NB_BLOCK_DEBUT;
			yAct = CAS_HAUTEUR_MAT - 1;
			dernierT = CSLP_GetElapsedTime(clockT);
			niveau = 0;
			level = 0;
			vitesse = 1;
			cas_new_line(&xAct, &yAct, matrice, &sensAct, nbAct);

			while(getch() != ERR)
				;
		}

		if(niveau == CAS_HAUTEUR_MAT) {
			jouer_son(GAGNE);
			cas_couleur_level(level, 1);
			cas_perdu_anim(matrice);
			level++;

			if(level % 5 != 0) {
				cas_couleur_level(level, 0);
				cas_resize_cadre_anim(CAS_POS_MAT_X - 2,
				CAS_POS_MAT_Y - 1,
				(CAS_LARGEUR_BLOCK + 2) * (CAS_LARGEUR_MAT) + 1,
				(CAS_HAUTEUR_BLOCK + 2) * (CAS_HAUTEUR_MAT),
				CAS_PLEIN, -(CAS_LARGEUR_BLOCK + 2));
				CAS_POS_MAT_X += CAS_LARGEUR_BLOCK + 2;
				CAS_LARGEUR_MAT -= 2;
			}
			else {
				cas_couleur_level(level, 0);
				cas_resize_cadre_anim(CAS_POS_MAT_X - 2,
				CAS_POS_MAT_Y - 1,
				(CAS_LARGEUR_BLOCK + 2) * (CAS_LARGEUR_MAT) + 1,
				(CAS_HAUTEUR_BLOCK + 2) * (CAS_HAUTEUR_MAT),
				CAS_PLEIN, 4 * (CAS_LARGEUR_BLOCK + 2));
				CAS_POS_MAT_X -= 4 * (CAS_LARGEUR_BLOCK + 2);
				CAS_LARGEUR_MAT += 8;
				vitesse += 0.5;
			}

			if(nbAct < CAS_NB_BLOCK_MAX)
				nbAct += 1;

			yAct = CAS_HAUTEUR_MAT - 1;
			dernierT = CSLP_GetElapsedTime(clockT);
			niveau = 0;
			cas_new_line(&xAct, &yAct, matrice, &sensAct, nbAct);
			cas_afficher(matrice, nbAct, level, niveau);

			while(getch() != ERR)
				;
		}

		if(action == CAS_POSER) {
			jouer_son(TOWERPOSER);
			nbAct = cas_etat_jeu(xAct, yAct, matrice, nbAct);
			yAct--;
			niveau++;
			cas_new_line(&xAct, &yAct, matrice, &sensAct, nbAct);
			if(niveau < CAS_HAUTEUR_MAT) {
				cas_afficher(matrice, nbAct, level, niveau);
			}
			dernierT = CSLP_GetElapsedTime(clockT);
		}

		if(CSLP_GetElapsedTime(clockT) - dernierT > (delai[niveau] / vitesse) / 1000.f) {
			cas_bouger(&xAct, &yAct, matrice, &sensAct, nbAct);
			dernierT = CSLP_GetElapsedTime(clockT);
			cas_afficher(matrice, nbAct, level, niveau);
		}
		else if(vitesse == 0.f) {
			Log_full(LOG_DEFAULT, "casino: dernierT", dernierT * 1000.0);
			Log_full(LOG_DEFAULT, "casino: elapsed time", CSLP_GetElapsedTime(clockT) * 1000.0);
			Log_full(LOG_DEFAULT, "casino: diff time", (CSLP_GetElapsedTime(clockT) - dernierT) * 1000.0);
			Log_full(LOG_DEFAULT, "casino: delay(level)", delai[niveau]);
			Log_full(LOG_DEFAULT, "casino: speed (x10)", vitesse * 10.f);
			Log_full(LOG_DEFAULT, "casino: condition required", (delai[niveau] / vitesse));
			Log_full(LOG_DEFAULT, "casino: #######################", 0);
		}

		if(action == CAS_QUITTER)
			break;

		CSLP_Sleep(5);
	}

	clear();
	nodelay(stdscr, 0);
	return;
}

/****************************/

void cas_init(void) {
	CAS_LARGEUR_MAT = CAS_DEBUT_MAT_X - 10;
	CAS_HAUTEUR_MAT = CAS_DEBUT_MAT_Y;
	CAS_POS_MAT_X = CAS_DEBUT_POS_X + (5 * (CAS_LARGEUR_BLOCK + 2));
	CAS_POS_MAT_Y = CAS_DEBUT_POS_Y;

	clear();
	afficher_titre("TOWER BUILD");
	nodelay(stdscr, 1);
	cas_couleur_level(0, 0);
	cas_afficher_cadre(CAS_POS_MAT_X - 2,
	CAS_POS_MAT_Y - 1,
	(CAS_LARGEUR_BLOCK + 2) * (CAS_LARGEUR_MAT) + 1,
	(CAS_HAUTEUR_BLOCK + 2) * (CAS_HAUTEUR_MAT),
	CAS_PLEIN);
	refresh();
	CSLP_Sleep(1000);
	cas_resize_cadre_anim(CAS_POS_MAT_X - 2,
	CAS_POS_MAT_Y - 1,
	(CAS_LARGEUR_BLOCK + 2) * (CAS_LARGEUR_MAT) + 1,
	(CAS_HAUTEUR_BLOCK + 2) * (CAS_HAUTEUR_MAT),
	CAS_PLEIN, 5 * (CAS_LARGEUR_BLOCK + 2));
	CAS_LARGEUR_MAT = CAS_DEBUT_MAT_X;
	CAS_POS_MAT_X -= 5 * (CAS_LARGEUR_BLOCK + 2);
	CSLP_Color(COLOR_WHITE, COLOR_BLACK);
	mvaddstr(8,  CAS_POS_TEXT_X, "Niveau ");
	mvaddstr(10,  CAS_POS_TEXT_X, "Hauteur : ");
	mvaddstr(20,  CAS_POS_TEXT_X, "Nombre de bloc(s) : ");
	mvaddstr(28,  CAS_POS_TEXT_X, "Commandes : ");
	mvaddstr(29,  CAS_POS_TEXT_X, "  <ESPACE> : POSER");
	mvaddstr(30,  CAS_POS_TEXT_X, "  '0' : QUITTER");
}

/****************************/

int cas_recupEvent(void) {
	int c;
	int retour = 0;

	c = getch();

	switch(c) {
	case ' ':
		retour = CAS_POSER;
		break;
	case '0':
		retour = CAS_QUITTER;
		break;
	default :
		break;
	}

	while(getch() != ERR)
		;

	return retour;
}

/****************************/

void cas_afficher(int matrice[][CAS_HAUTEUR_MAT], int nbAct, int level, int niveau) {
	int i, j;

	CSLP_Color(COLOR_WHITE, COLOR_BLACK);

	for(i = 0; i < CAS_NB_BLOCK_MAX - nbAct; i++)
		cas_afficher_vide(CAS_POS_TEXT_X + (i + nbAct) * (CAS_LARGEUR_BLOCK + 2), 22);

	mvprintw(8,  CAS_POS_TEXT_X + 8, "%d  ", level + 1);
	mvprintw(10,  CAS_POS_TEXT_X + 10, "%d ", niveau + 1);

	cas_couleur_level(level, 1);

	for(i = 0; i < nbAct; i++)
		cas_afficher_block(CAS_POS_TEXT_X + i * (CAS_LARGEUR_BLOCK + 2), 22);

	for(i = 0; i < CAS_HAUTEUR_MAT; i++) {
		for(j = 0; j < CAS_LARGEUR_MAT; j++) {
			if(matrice[j][i] == CAS_B_A_CHANGER) {
				matrice[j][i] =  CAS_BLOCK;
				cas_couleur_level(level, 1);
				cas_afficher_block(j * (CAS_LARGEUR_BLOCK + 2) + CAS_POS_MAT_X,
				i * (CAS_HAUTEUR_BLOCK + 2) + CAS_POS_MAT_Y);
			}
			else if(matrice[j][i] == CAS_V_A_CHANGER) {
				matrice[j][i] = CAS_VIDE;
				cas_couleur_level(level, 0);
				cas_afficher_vide(j * (CAS_LARGEUR_BLOCK + 2) + CAS_POS_MAT_X,
				i * (CAS_HAUTEUR_BLOCK + 2) + CAS_POS_MAT_Y);
			}
		}
	}

	refresh();
}

/****************************/

void cas_afficher_block(int x, int y) {
	int i, j;

	move(y, x);
	addch('\\');

	for(i = 0; i < CAS_LARGEUR_BLOCK; i++)
		addch(' ');

	addch('/');

	for(i = 0; i < CAS_HAUTEUR_BLOCK; i++) {
		move(++y, x);
		addch(' ');

		for(j = 0; j < CAS_LARGEUR_BLOCK; j++)
			addch(CAS_PLEIN);

		addch(' ');
	}

	move(++y, x);
	addch('/');

	for(i = 0; i < CAS_LARGEUR_BLOCK; i++)
		addch(' ');

	addch('\\');

}

/****************************/

void cas_bouger(int *x, int *y, int matrice[][CAS_HAUTEUR_MAT], int *sens, int nb) {
	if(*x + nb >= CAS_LARGEUR_MAT && *sens ==  CAS_VERS_DROITE) {
		*sens = CAS_VERS_GAUCHE;
		jouer_son(TOWERCOTE);
	}
	else if(*x <= 0 && *sens == CAS_VERS_GAUCHE) {
		*sens = CAS_VERS_DROITE;
		jouer_son(TOWERCOTE);
	}

	if(*sens == CAS_VERS_GAUCHE) {
		matrice[*x + nb - 1][*y] = CAS_V_A_CHANGER;
		matrice[*x - 1][*y] = CAS_B_A_CHANGER;
		*x -= 1;
	}
	else if(*sens == CAS_VERS_DROITE) {
		matrice[*x][*y] = CAS_V_A_CHANGER;
		matrice[*x + nb][*y] = CAS_B_A_CHANGER;
		*x += 1;
	}
}

/****************************/

void cas_new_line(int *x, int *y, int matrice[][CAS_HAUTEUR_MAT], int *sens, int nb) {
	int leRand, i;

	leRand = rand() % 2;

	if(leRand == 0) {
		for(i = 0; i < nb; i++)
			matrice[i][*y] = CAS_B_A_CHANGER;

		*sens = CAS_VERS_DROITE;
		*x = 0;
	}

	else if(leRand == 1) {
		for(i = 0; i < nb; i++)
			matrice[CAS_LARGEUR_MAT - i - 1][*y] = CAS_B_A_CHANGER;

		*sens = CAS_VERS_GAUCHE;
		*x = CAS_LARGEUR_MAT - nb;
	}
}

/****************************/

void cas_descendre_block_anim(int x, int y, int matrice[][CAS_HAUTEUR_MAT], int nb) {
	int i, j;

	CSLP_Sleep(100);

	for(j = 0; j < nb; j++)
		matrice[x + j][y] = CAS_VIDE;

	for(i = y; i < CAS_HAUTEUR_MAT; i++) {
		for(j = 0; j < nb; j++) {
			CSLP_Color(COLOR_RED, COLOR_RED);
			cas_afficher_block(CAS_POS_MAT_X + (x + j) * (CAS_LARGEUR_BLOCK + 2),
			CAS_POS_MAT_Y + i * (CAS_HAUTEUR_BLOCK + 2));
		}

		refresh();

		for(j = 0; j < nb; j++) {
			CSLP_Color(COLOR_BLACK, COLOR_BLACK);
			matrice[x + j][i] = CAS_V_A_CHANGER;
			cas_afficher_vide(CAS_POS_MAT_X + (x + j) * (CAS_LARGEUR_BLOCK + 2),
			CAS_POS_MAT_Y + i * (CAS_HAUTEUR_BLOCK + 2));
		}

		jouer_son(TOWERDESCENDRE);
		CSLP_Sleep(100);
	}

	jouer_son(TOWERBOOM);
	CSLP_Sleep(250);

	while(getch() != ERR)
		;

}

/****************************/

void cas_perdu_anim(int matrice[][CAS_HAUTEUR_MAT]) {
	int i, j;

	CSLP_Sleep(200);

	for(i = CAS_HAUTEUR_MAT - 1; i >= 0; i--) {
		for(j = 0; j < CAS_LARGEUR_MAT; j++)
			cas_afficher_block(CAS_POS_MAT_X + j * (CAS_LARGEUR_BLOCK + 2),
			CAS_POS_MAT_Y + i * (CAS_HAUTEUR_BLOCK + 2));

		refresh();
		CSLP_Sleep(50);
	}

	CSLP_Sleep(500);
	CSLP_Color(COLOR_BLACK, COLOR_BLACK);

	for(i = CAS_HAUTEUR_MAT - 1; i >= 0; i--) {
		for(j = 0; j < CAS_LARGEUR_MAT; j++) {
			cas_afficher_vide(CAS_POS_MAT_X + j * (CAS_LARGEUR_BLOCK + 2),
			CAS_POS_MAT_Y + i * (CAS_HAUTEUR_BLOCK + 2));
			matrice[j][i] = CAS_VIDE;
		}

		refresh();
		CSLP_Sleep(50);
	}

	CSLP_Sleep(500);
}

/****************************/

void cas_afficher_vide(int x, int y) {
	int i, j;

	for(i = 0; i < CAS_HAUTEUR_BLOCK + 2; i++) {
		move(y + i, x);

		for(j = 0; j < CAS_LARGEUR_BLOCK + 2; j++)
			addch(' ');
	}

}

/****************************/

int cas_etat_jeu(int x, int y, int matrice[][CAS_HAUTEUR_MAT], int nb) {
	int i, xPerdu = 1000, nbPerdu = 0;


	if(y < CAS_HAUTEUR_MAT - 1) {
		for(i = 0; i < nb; i++) {
			if(matrice[x + i][y + 1] % 2 == CAS_VIDE) {
				if(xPerdu == 1000)
					xPerdu = x + i;

				nbPerdu++;
			}
		}

		if(nbPerdu)
			cas_descendre_block_anim(xPerdu, y, matrice, nbPerdu);
	}

	return nb - nbPerdu;
}

/****************************/

void cas_afficher_cadre(int x, int y, int w, int h, int car) {
	int i;

	move(y, x);

	for(i = 0; i < w + 2; i++)
		addch(car);

	addch(car);

	move(h + y + 1, x);

	for(i = 0; i < w + 2; i++)
		addch(car);

	addch(car);


	move(y + 1, x);

	for(i = 0; i < h; i++) {
		mvaddch(y + i + 1, x, car);
		addch(car);
	}

	move(y + 1, x + w + 1);

	for(i = 0; i < h; i++) {
		mvaddch(y + i + 1, x + w + 1, car);
		addch(car);
	}
}

/****************************/

void cas_resize_cadre_anim(int x, int y, int w, int h, int car, int plusX) {
	int i;

	jouer_son(TOWERTRANSITION);

	if(plusX >= 0) {
		for(i = 0; i <= plusX; i++) {
			cas_afficher_cadre(x - i, y, w + i * 2, h, car);
			refresh();
			CSLP_Sleep(80);
			cas_afficher_cadre(x - i, y, w + i * 2, h, ' ');
		}
	}
	else {
		for(i = 0; i > plusX; i--) {
			cas_afficher_cadre(x - i, y, w + i * 2, h, car);
			refresh();
			CSLP_Sleep(80);
			cas_afficher_cadre(x - i, y, w + i * 2, h, ' ');
		}
	}

	cas_afficher_cadre(x - plusX, y, w + plusX * 2, h, car);
}

/****************************/

void cas_couleur_level(int level, int doubleBool) {
	if(doubleBool) {
		if(level % 5 == 0)
			CSLP_Color(COLOR_CYAN, COLOR_CYAN);
		else if(level % 5 == 1)
			CSLP_Color(COLOR_GREEN, COLOR_GREEN);
		else if(level % 5 == 2)
			CSLP_Color(COLOR_YELLOW, COLOR_YELLOW);
		else if(level % 5 == 3)
			CSLP_Color(COLOR_CYAN, COLOR_BLUE);
		else if(level % 5 == 4)
			CSLP_Color(COLOR_MAGENTA, COLOR_MAGENTA);
	}
	else {
		if(level % 5 == 0)
			CSLP_Color(COLOR_CYAN, COLOR_BLACK);
		else if(level % 5 == 1)
			CSLP_Color(COLOR_GREEN, COLOR_BLACK);
		else if(level % 5 == 2)
			CSLP_Color(COLOR_YELLOW, COLOR_BLACK);
		else if(level % 5 == 3)
			CSLP_Color(COLOR_CYAN, COLOR_BLACK);
		else if(level % 5 == 4)
			CSLP_Color(COLOR_MAGENTA, COLOR_BLACK);
	}
}
